<?php
/**
 * Poll
 *
 * Отвечает  голосование (оценки +/-1) для постов, пользователей, комментариев и т.д.
 *
 * @author 
 * @version 1.1
 */
class Poll {

  static $markMinus = -1.0;
  static $markPlus = 1.0;
	public function __construct(){}
	/**
	 * Функция устанавливает значение оценки
	 *
	 * @param integer $essenceType -  условный идентификатор сущности
	 * @param integer $essenceId - идентификатор элемента в таблице
	 * @param float $mark - устанавливаемая оценка
	 * @param bool $selfPoll - возможность выставлять оценку самому себе
	 * @param integer $markType - тип оценки: 0 - обычная, 1 - специально для подсчёта кол-ва за и против
	 * @return bool - возвращает true в случае, если оценка установлена успешно,
	 *                false - в противоположном случае
	 */
	static public function setPoll($essenceType, $essenceId, $mark, $selfPoll = false, $markType = 0){

	  $objSession = User_Session::instance();
	  $userId = $objSession->getUserId();
	  Statistics::addEvent(3, $userId);//добавляем в статистику

/*	  if(!$userId)
	    throw new Exception('Только авторизованные пользователи могут выставлять оценки');*/
	  if ($selfPoll == false && !(Poll::_baseIsUserCorrect($userId, $essenceId, $essenceType, $markType)))
	    throw new Exception('Невозможно голсовать за самого себя!');
	  if(Poll::isPollSet($userId, $essenceType, $essenceId))
			throw new Exception('Невозможно выставить оценку повторно!');
		if(!Poll::_bazeSetPoll($userId, $essenceType, $essenceId, $mark))
			throw new Exception('Невозможно выставить оценку по техническим причинам!');
	  if(!Poll::_setAveragePoll($essenceType, $essenceId, $mark, $markType))
			throw new Exception('Невозможно пересчитать среднюю оценку по техническим причинам!');
		return true;
	}





	/**
	 * Функция проверяет, имеет ли право пользователь ставить оценку элементу
	 *
	 * @param integer $userId - идентификатор текущего пользователя
	 * @param integer $essenceId - идентификатор элемента в таблице
	 * @param integer $essenceType - условный идентификатор сущности
	 * @return bool - возвращает true, если пользователь имеет право ставить оценку,
	 *                false - в противоположном случае
	 */
	static private function _baseIsUserCorrect($userId, $essenceId, $essenceType, $markType = 0) {
//	  if ($essenceType == 2 || $essenceType == 8)
//	    return true;
		$strTable = Service_Essence::getEssenceTypeName($essenceType);
		$essenceIdField = Service_Essence::getEssenceIdFieldName($essenceType);
		$dopAnd = ' AND `id_user` = ' . $userId;
		if ($markType == 1){
			$strTable = 'offer';
			$dopAnd = ' AND `id_user_first_offered` = ' . $userId . ' AND `essence_type` = ' . Service_Essence::getEssenceTypeID($essenceType);
		}
	  $objDB = Service_Database::instance();
	  if(!$strTable || $strTable == '')
  	  return false;
		$stmt = "SELECT `" . $essenceIdField . "` FROM `" . DB_PREFIX.$strTable . "`
				WHERE `" . $essenceIdField . "` = " . $essenceId . $dopAnd;
    return (sizeof($objDB->selectOne($stmt)) > 0) ? false : true;  //Осуществляем SQL-запрос
	}

	/**
	 * Функция проверяет, голосовал ли уже пользователь
	 *
	 * @param integer $essenceType - условный идентификатор сущности
	 * @param integer $essenceId - идентификатор элемента в таблице
	 * @param integer $authorId - идентификатор автора
	 * @param integer $userId - идентификатор текущего пользователя
	 * @return bool - возвращает true, если пользователь голосовал
	 *                false - в противоположном случае
	 */
	static public function getSessionUserPoll($essenceType, $essenceId, $authorId, $userId = NULL) {
	  if(!$userId){
	    $objSession = User_Session::instance();
      $userId = $objSession->getUserId();
	  }
    if(!$userId)
      return NULL;
    if($authorId == $userId)
      return 0;
	  $objDB = Service_Database::instance();
		$stmt = "SELECT `mark` FROM `".DB_PREFIX."poll`
				WHERE `id_essence`='" . $essenceId . "' AND `essence_type`='" . $essenceType . "' AND `id_user`='" . $userId . "'";
		return $objDB->selectSimpleField($stmt);
	}

	/**
	 * Функция проверяет, ставил ли данный пользователь оценку этому элементу
	 *
	 * @param integer $userId - идентификатор текущего пользователя
	 * @param integer $essenceType -  условный идентификатор сущности
	 * @param integer $essenceId - идентификатор элемента в таблице
	 * @return bool - возвращает true в случае, если пользователь оценку ещё не ставил,
	 *                false - если ставил
	 */
	static public function isPollSet($userId, $essenceType, $essenceId){
		$objDB = Service_Database::instance();
		$stmt = "SELECT `".DB_PREFIX."poll`.`id_poll` FROM `".DB_PREFIX."poll`
				WHERE `".DB_PREFIX."poll`.`id_user`='" . $userId . "'
				AND `".DB_PREFIX."poll`.`essence_type`='" . $essenceType . "'
				AND `".DB_PREFIX."poll`.`id_essence`='" . $essenceId . "'";
		return (sizeof($objDB->selectOne($stmt)) > 0) ? true : false;  //Осуществляем SQL-запрос
	}
	/**
	 * Функция устанавливает значение оценки
	 *
	 * @param integer $userId - идентификатор текущего пользователя
	 * @param integer $essenceType -  условный идентификатор сущности
	 * @param integer $essenceId - идентификатор элемента в таблице
	 * @param integer $mark - усанавливаемая оценка
	 * @return bool - возвращает true в случае, если оценка установлена успешно,
   *                false - в противоположном случае
	 */
	static private function _bazeSetPoll($userId, $essenceType, $essenceId, $mark){
	  $objDB = Service_Database::instance();
		$stmt = "INSERT INTO `".DB_PREFIX."poll`
				     (`".DB_PREFIX."poll`.`id_user`, `".DB_PREFIX."poll`.`essence_type`, `".DB_PREFIX."poll`.`id_essence`, `".DB_PREFIX."poll`.`mark`, `".DB_PREFIX."poll`.`creation`)
				     VALUES('" . $userId . "', '" . $essenceType . "', '" . $essenceId . "', '" . $mark . "', '" . Service_Date::gLocalTime2BD() . "')";
		return $objDB->query($stmt);
	}
	/**
	 * Функция устанавливает среднюю оценку
	 *
	 * @param integer $essenceType -  условный идентификатор сущности
	 * @param integer $essenceId - идентификатор элемента в таблице
	 * @param float $mark - усанавливаемая оценка
	 * @return bool - возвращает true в случае, если оценка установлена успешно,
	 *                false - в противоположном случае
	 */
	static private function _setAveragePoll($essenceType, $essenceId, $markif, $markType = 0){
		$arrPoll = Poll::_baseGetItemPolls($essenceType, $essenceId);
		$strTable = Service_Essence::getEssenceTypeName($essenceType);
		Poll::_bazeSetAveragePoll($strTable, $essenceId, $arrPoll['marks_minus'], $arrPoll['marks_plus'], $markType);
		return true;
	}
	/**
	 * Функция устанавливает суммарную оценку и сколько раз этому элементу ставилась оценка
	 *
	 * @param integer $essenceType -  условный идентификатор сущности
	 * @param integer $essenceId - идентификатор элемента в таблице
	 * @return array - возвращает суммарную оценку и сколько раз этому элементу ставилась оценка
	 *                 в виде массива из двух элементов
	 */
	static private function _baseGetItemPolls($essenceType, $essenceId){
  	$objDB = Service_Database::instance();
  	$retArray = array();
  	$stmt = "SELECT COUNT(`".DB_PREFIX."poll`.`id_poll`) AS `amount`
      	     FROM `".DB_PREFIX."poll`
      			 WHERE `".DB_PREFIX."poll`.`essence_type`='" . $essenceType . "'
      			 AND `".DB_PREFIX."poll`.`id_essence`='" . $essenceId . "'
      			 AND `".DB_PREFIX."poll`.`mark`='-1'
      	     GROUP BY `".DB_PREFIX."poll`.`essence_type`, `".DB_PREFIX."poll`.`id_essence`";
  	$retArray['marks_minus'] = $objDB->selectSimpleField($stmt);
  	if (is_int($retArray['marks_minus'])) $retArray['marks_minus'] = 0; 
  	$stmt = "SELECT COUNT(`".DB_PREFIX."poll`.`id_poll`) AS amount
      	     FROM `".DB_PREFIX."poll`
      			 WHERE `".DB_PREFIX."poll`.`essence_type`='" . $essenceType . "'
      			 AND `".DB_PREFIX."poll`.`id_essence`='" . $essenceId . "'
      			 AND `".DB_PREFIX."poll`.`mark`=1
      	     GROUP BY `".DB_PREFIX."poll`.`essence_type`, `".DB_PREFIX."poll`.`id_essence`";
  	$retArray['marks_plus'] = $objDB->selectSimpleField($stmt);
  	return $retArray;
	}
	/**
	 * Функция устанавливает средние значение оценки элементу
	 *
	 * @param string $strTable - название таблицы, в каторую необходимо внести изменения
	 * @param integer $essenceId - условный идентификатор сущности
	 * @param float $averagePoll - среднее значение оценки
	 * @return bool - возвращает true, если изменения в базу внесены успешно,
	 *                false - в противоположном случае
	 */
	static private function _bazeSetAveragePoll($strTable, $essenceId, $marksMinus, $marksPlus, $markType = 0){
	$objDB = Service_Database::instance();
	if(!$strTable || $strTable == '')
  		return false;
	$essenceIdField = Service_Essence::getEssenceIdFieldName($strTable);

			$arrUpdate = array('marks_minus' => $marksMinus,
													'marks_plus' => $marksPlus);
			if ($markType == 1){
				$strTable = 'offer';
				$arrUpdate['amount'] = self::calculateMark($marksMinus, $marksPlus, 1); // доп-но средняя оценка
			}
			$arrWhere = array($essenceIdField => $essenceId);

	return $objDB->update(DB_PREFIX.$strTable, $arrUpdate, $arrWhere);
	}
	/**
	 * Подсчитывает среднюю оценку исходя из количества положительных и отрицательных оценок
	 *
	 * @param integer $marksMinus
	 * @param integer $marksPlus
	 * @param integer $markType - тип оценки: 0 - обычная, 1 - специально для подсчёта кол-ва за и против
	 * @return integer
	 */
	public static function calculateMark($marksMinus, $marksPlus, $markType = 0) {
	  if($markType == 0)
	  	return round($marksMinus * self::$markMinus + $marksPlus * self::$markPlus);
	  elseif ($markType == 1)
	  	return ($marksPlus - $marksMinus);
	}
	/**
	 * Подсчитывает среднюю оценку исходя из количества положительных и отрицательных оценок
	 *
	 * @param integer $marksMinus
	 * @param integer $marksPlus
	 * @return integer
	 */
	public static function calculateFloatMark($marksMinus, $marksPlus) {
	  return $marksMinus * self::$markMinus + $marksPlus * self::$markPlus;
	}
	/**
	 * Возращает текущую оценку
	 *
	 * @param integer $essenceType
	 * @param integer $essenceId
	 * @return integer
	 */
	public static function getCurrentMark($essenceType, $essenceId) {
	  $arrMarks = self::_baseGetItemPolls($essenceType, $essenceId);
	  return self::calculateMark($arrMarks['marks_minus'], $arrMarks['marks_plus']);
	}

	/**
	 * Возвращает количество оценок
	 *
	 * @param int $essenceType - Тип сущности
	 * @param int $essenceId - ID сущности
	 * @return количество оценок
	 */
	public static function getPlusAndMinusMarkCount($essenceType, $essenceId){
		return self::_baseGetItemPolls($essenceType, $essenceId);
	}
	
	/**
	 * Метод устанавливает флаг, не позволяющий автору голосовать самому за себя
	 *
	 * @param array $arrEssences
	 * @return array
	 */
	public static function setSessionUserPoll($arrEssences){
		$objSession = User_Session::instance();
	  $size = sizeof($arrEssences);
		for ($i=0; $i < $size; $i++){
			if ($objSession->getUserId() != 0){
				if(is_NULL($arrEssences[$i]['session_user_poll'])){
					if ($objSession->getUserId() == $arrEssences[$i]['ID_user'])
						$arrEssences[$i]['session_user_poll'] = 0; // если залогинен автор сущности, то он не может голосовать сам за себя
				}
			}
		}
		return $arrEssences;		
	}
}
?>